#include "IrradianceCubemapProcess.h"
#include "Utils/LogUtil.h"
#include "Render/RenderState.h"
#include "Core/CoreGlobals.h"
#include "Game/Scene/Entity.h"
#include "Game/Component/Model.h"
#include "Render/Buffer/VertexBuffer.h"
#include "Render/Buffer/IndexBuffer.h"
#include "Render/Buffer/CustomBuffer.h"
#include "LocalShader.h"
#include "Utils/FileUtil.h"
#include "Game/GameState.h"
#include "Render/VulkanTool.h"
#include "Render/Texture/CubemapTexture.h"


void IrradianceCubemapProcess::OnInit()
{
	mWidth = 512;
	mHeight = 256;

	mDeltaPhi = Math::M_2PI / 180.0f;
	mDeltaTheta = Math::M_HALF_PI / 64.0f;

	mPushBlock.deltaPhi = mDeltaPhi;
	mPushBlock.deltaTheta = mDeltaTheta;

	ENQUEUE_RENDER_COMMAND(BuildModel)([this](VkCommandBuffer commandBuffer)
		{
			mCubemapTexture = CubemapTexture::Builder()
				.SetAutoMip()
				.SetPaths({
				"Hdr\\LoftHall_nz.hdr",
				"Hdr\\LoftHall_pz.hdr",
				"Hdr\\LoftHall_py.hdr",
				"Hdr\\LoftHall_ny.hdr",
				"Hdr\\LoftHall_px.hdr",
				"Hdr\\LoftHall_nx.hdr"
					})
				.SetFormat(VK_FORMAT_R32G32B32A32_SFLOAT)
				.Build(this, "CubemapTexture");

			mCubemapSampler = RHISampler::Builder()
				.SetAddressModeU(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE)
				.SetAddressModeV(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE)
				.SetAddressModeW(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE)
				.SetCompareOp(VK_COMPARE_OP_NEVER)
				.SetMaxLod(mCubemapTexture->GetMipLevels())
				.SetBorderColor(VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE)
				.Build(this, "CubemapSampler");

			mCommandBuffer = RHICommandBuffer::Builder()
				.SetQueue(VK_QUEUE_GRAPHICS_BIT)
				.SetCount(1)
				.SetCommandBufferUsage(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT)
				.Build();

			mDescriptor = RHIDescriptor::Builder()
				.PushShader<GenIrradianceCubemapVertexShader>()
				.PushShader<GenIrradianceCubemapFragmentShader>()
				.SetDescriptorCount(0, 1)
				.Build();

			mDescriptor->SetValue("samplerEnvMap", mCubemapTexture, mCubemapSampler);
			mDescriptorMask = mDescriptor->AllocateDescriptor();

			mColorRenderTarget = ColorRenderTarget::Builder()
				.SetFormat(VK_FORMAT_R32G32B32A32_SFLOAT)
				.SetWidth(mWidth)
				.SetHeight(mHeight)
				.SetUsage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)
				.SetStoreOp(VK_ATTACHMENT_STORE_OP_STORE)
				.SetFinalLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
				.SetClearColorValue({ 0.1f, 0.1f, 0.1f, 1.f })
				.Build(this, "ColorRenderTarget");

			mPipeline = GraphicsPipeline::Builder()
				.SetDescriptor(mDescriptor)
				.AddColorRenderTarget(mColorRenderTarget)
				.SetDstStageMask(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)
				.SetDstAccessMask(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT)
				.SetSrcStageMask(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)
				.SetSrcAccessMask(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT)
				.Build();

			mRenderPass = RHIRenderPass::Builder()
				.AddRenderTarget(mColorRenderTarget)
				.AddPipeline(mPipeline)
				.SetSrcStageMask(VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT)
				.SetSrcAccessMask(VK_ACCESS_SHADER_READ_BIT)
				.SetDstStageMask(VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT)
				.SetDstAccessMask(VK_ACCESS_SHADER_READ_BIT)
				.Build();

			mFrameBuffer = RHIFrameBuffer::Builder()
				.SetRenderPass(mRenderPass)
				.Build();
		});
}

void IrradianceCubemapProcess::OnTick(float deltaTime)
{
	if (GGameState->GetFrameAmount() > 0)
		return;

	ENQUEUE_RENDER_COMMAND(RecordCommand)([this](VkCommandBuffer commandBuffer)
		{
			VkCommandBuffer offlineCommandBuffer = mCommandBuffer->BeginCommandBuffer();


			VkRenderPassBeginInfo renderPassBeginInfo = mFrameBuffer->GetRenderPassBeginInfo();

			vkCmdBeginRenderPass(offlineCommandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);

			VkViewport viewport{ 0, 0, mWidth, mHeight, 0, 1 };
			vkCmdSetViewport(offlineCommandBuffer, 0, 1, &viewport);

			VkRect2D scissor{ 0, 0, mWidth, mHeight };
			vkCmdSetScissor(offlineCommandBuffer, 0, 1, &scissor);

			vkCmdBindPipeline(offlineCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, mPipeline->GetPipeline());

			vkCmdBindDescriptorSets(offlineCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, mPipeline->GetPipelineLayout(), 0, 1, &mDescriptorMask.GetDescriptorSet(), 0, nullptr);

			vkCmdPushConstants(offlineCommandBuffer, mPipeline->GetPipelineLayout(), VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushBlock), &mPushBlock);

			vkCmdDraw(offlineCommandBuffer, 3, 1, 0, 0);

			vkCmdEndRenderPass(offlineCommandBuffer);


			mCommandBuffer->FlushCommandBuffer(offlineCommandBuffer);

			vkQueueWaitIdle(GVulkanRHI->GetQueue());

			mCommandBuffer.SafeRelease();
			mDescriptor.SafeRelease();
			mPipeline.SafeRelease();
			mRenderPass.SafeRelease();
			mFrameBuffer.SafeRelease();
		});
}

void IrradianceCubemapProcess::OnResize()
{

}
